package @controllerPackage@;

import org.hibernate.criterion.Criterion;

import java.util.List;
import java.io.Serializable;

import @modelPackage@.*;

/**
 * Abstract class which represents list of entities
 * created: 28.07.2009
 *
 * @author Michal Rost
 * @param <T> entity data type (identifier for persistent class)
 * @param <ID> id property data type
 */
public abstract class HibernateList<T, ID extends Serializable> {

  protected HibernateDAO<T, ID> dao;
  protected int firstResult;
  protected int totalResults;
  protected int maxPageResults;
  protected Criterion[] criterions;
  protected String orderBy;
  protected boolean orderAsc = true;
  protected List<T> resultList;
  protected boolean changed;

  /**
   * Constructor, initialization of list
   */
  public HibernateList() {
    dao = null;
    changed = true;
    firstResult = 0;
    totalResults = 0;
    maxPageResults = 25;
    resultList = null;
  }

  /**
   * Returns entity DAO object
   *
   * @return number of first row on actual page
   */
  public HibernateDAO<T, ID> getDao() {
    return dao;
  }

  /**
   * Sets entity DAO object
   *
   * @param dao entity DAO object
   */
  public void setDao(HibernateDAO<T, ID> dao) {
    this.dao = dao;
  }


  /**
   * Returns number of first row on actual page
   *
   * @return number of first row on actual page
   */
  public int getFirstResult() {
    return firstResult;
  }

  /**
   * Returns number of first row on previous page
   *
   * @return number of first row on previous page
   */
  public int getPrevFirstResult() {
    return getFirstResult() - getMaxPageResults();
  }

  /**
   * Returns number of first row on next page
   *
   * @return number of first row on next page
   */
  public int getNextFirstResult() {
    return getFirstResult() + getMaxPageResults();
  }

  /**
   * Returns number of first row on last page
   *
   * @return number of first row on last page
   */
  public int getLastFirstResult() {
    return getTotalResults() - getTotalResults() % getMaxPageResults();
  }

  /**
   * Sets number of first row on page
   *
   * @param firstResult number of first row on page
   */
  public void setFirstResult(int firstResult) {
    setChanged(true);
    this.firstResult = firstResult;
  }

  /**
   * Returns total number of rows
   *
   * @return total rows
   */
  public int getTotalResults() {
    return totalResults;
  }

  /**
   * Returns total number of pages
   *
   * @return total pages
   */
  public int getPageCount() {
    return (int) Math.ceil((double) getTotalResults() / getMaxPageResults());
  }

  /**
   * Checks whether previous page exists
   *
   * @return true/false previous page exists/not exists
   */
  public boolean getPrevPageExists() {
    return (getFirstResult() - getMaxPageResults()) >= 0;
  }

  /**
   * Checks whether next page exists
   *
   * @return true/false next page exists/not exists
   */
  public boolean getNextPageExists() {
    return (getFirstResult() + getMaxPageResults()) < getTotalResults();
  }

  /**
   * Get array of criteriums
   *
   * @return array of criteriums
   */
  public Criterion[] getCriterions() {
    return criterions;
  }

  /**
   * Sests criteriums for query
   *
   * @param criterions criteriums
   */
  public void setCriterions(Criterion[] criterions) {
    setChanged(true);
    this.criterions = criterions;
  }

  /**
   * Returns maximal number of rows per page
   *
   * @return maximal number of rows per page
   */
  public int getMaxPageResults() {
    return maxPageResults;
  }

  /**
   * Sets maximal number of rows per page
   *
   * @param maxPageResults maximal number of rows per page
   */
  public void setMaxPageResults(int maxPageResults) {
    setChanged(true);
    this.maxPageResults = maxPageResults;
  }

  /**
   * Returns name of "order by" column
   *
   * @return name of "order by" column
   */
  public String getOrderBy() {
    return orderBy;
  }

  /**
   * Sets name of "order by" column
   *
   * @param orderBy name of "order by" column
   */
  public void setOrderBy(String orderBy) {
    setChanged(true);
    this.orderBy = orderBy;
  }

  /**
   * Returns order direction
   *
   * @return true if order is ascending
   */
  public boolean isOrderAsc() {
    return orderAsc;
  }

  /**
   * Returns order direction
   *
   * @param orderAsc ordering direction (true for ascending, false for descending)
   */
  public void setOrderAsc(boolean orderAsc) {
    setChanged(true);
    this.orderAsc = orderAsc;
  }

  /**
   * Returns state variable changed
   *
   * @return true if query has changed
   */
  protected boolean isChanged() {
    return changed;
  }

  /**
   * Sets state variable changed
   *
   * @param changed true if query has changed
   */
  protected void setChanged(boolean changed) {
    this.changed = changed;
  }

  /**
   * Returns result list
   *
   * @return result list
   */
  public List<T> getResultList() {
    if (changed) {
      loadResultList();
      setChanged(false);
    }
    return resultList;
  }

  /**
   * Loads result list from database
   */
  protected void loadResultList() {

    // Check whether DAO object is present
    if (getDao() == null) {
      throw new IllegalStateException("DAO has not been set");
    }

    // Selects result list and total number of results
    resultList = getDao().findByCriteria(getFirstResult(), getMaxPageResults(), getOrderBy(), isOrderAsc(), getCriterions());   
    totalResults = getDao().findCountByCriteria(getCriterions());
  }
}
